from ..errors import CardGameError, UnimplementedError
from ..errors import NoSuchUserError, NoSuchCardError, NoSuchCollectionError

class GameController(object):
    """
    Manages changes to the state of the game, 
    such as card movements.
    
    Each game command returns True if it was 
    permitted and successed and False otherwise, 
    followed by an optional dictionary of any 
    results (e.g. a randomly-chosen card)
    """
    
    def __init__(self, permissions=None, cardcollections=None):
        """
        Requires a PermissionsController to 
        approve each change.
        
        Requires a dictionary of CardController 
        objects to represent the table, players' 
        hands and decks, etc.
        Structure:
            { tables: {<dictionary>},
              decks: {<dictionary>},
              hands: {<dictionary>},
              other: {<dictionary>} }
        """
        self.permissions = permissions
        self.cardcollections = cardcollections
        
    def move_card_coordinates(self, user, card_id, table_id, new_coordinates):
        """
        Usage: move_card_coordinates(user, card_ID, table_ID, new_coordinates)
        Asks to have the card moved by the user to a new 
        position on the table (which may be a different 
        table than before).
        """
        return self.permissions.allowed(user,
                                        "move_card_coordinates",
                                        {'card_id':card_id,
                                         'table_id':table_id,
                                         'coordinates':new_coordinates},)
        
    def card_on_table(self, user, table_id, card_id):
        """
        Usage: on_table(user, table_ID, card_ID)
        Returns True if the card is on that table, 
        False otherwise
        """
        if (table_id in self.cardcollections["tables"]):
            return self.cardcollections["tables"][table_id].in_collection(card_id)
        else:
            raise NoSuchCollectionError(table_id)
    
    def remove_card_from_table(self, user, table_id, card_id):
        """
        Usage: remove_card_from_table(user, table_ID, card_ID)
        Tries to remove the card from the table.  Throws an 
        exception if the card is not already there.
        """
        if (table_id in self.cardcollections["tables"]):
            return self.cardcollections["tables"][table_id].remove_card(card_id)
        else:
            raise NoSuchCollectionError(table_id)
        
    def add_card_to_table(self, user, table_id, card_id, card_args):
        """
        Usage: add_card_to_table(user, table_id, card_ID, card_args)
        Tries to add the card to the deck along with the arguments
        """
        if (deck_id in self.cardcollections["tables"]):
            return self.cardcollections["tables"][table_id].add_card(card_id, args)
        else:
            raise NoSuchCollectionError(table_id)
        
    def card_in_deck(self, user, deck_id, card_id):
        """
        Usage: card_in_deck(user, deck_ID, card_ID)
        Returns True if the card is in that deck, 
        False otherwise
        """
        if (deck_id in self.cardcollections["decks"]):
            return self.cardcollections["decks"][deck_id].in_collection(card_id)
        else:
            raise NoSuchCollectionError(deck_id)
    
    def remove_card_from_deck(self, user, deck_id, card_id):
        """
        Usage: remove_card_from_deck(user, deck_ID, card_ID)
        Tries to remove the card from the deck.  Throws an 
        exception if the card is not already there.
        """
        if (deck_id in self.cardcollections["decks"]):
            return self.cardcollections["decks"][deck_id].remove_card(card_id)
        else:
            raise NoSuchCollectionError(deck_id)
        
    def add_card_to_deck(self, user, deck_id, card_id, card_args):
        """
        Usage: add_card_to_deck(user, deck_ID, card_ID, card_args)
        Tries to add the card to the deck along with the arguments
        """
        if (deck_id in self.cardcollections["decks"]):
            return self.cardcollections["decks"][deck_id].add_card(card_id, args)
        else:
            raise NoSuchCollectionError(deck_id)
        
        
    def bad_action(self, user):
        """
        Usage: bad_action(user)
        
        PermissionsControllers MUST report this action as 
        one not in their database, as it checks for just 
        such an ability to do so.
        """
        return self.permissions.allowed(user, "bad_action", {})